﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Threading;

namespace FileMonitor.Configuration.Prototype.BizProcess
{
    public abstract class BizProcessBase
    {
        private string _name;
        private NameValueCollection _extendableConfig;
        private Queue<ExcutedTask> _tasks = new Queue<ExcutedTask>();
        EventWaitHandle _wh = new AutoResetEvent(false);
        Thread _worker;
        readonly object _locker = new object();
        private readonly object _objEventExcuted = new object();

        public delegate void ExcutedHander(object sender, ExcutedEventArgs args);

        protected EventHandlerList Events;
      
        public event ExcutedHander Excuted;

        private BizProcessBase _nextBizProcess;

        private int _nextStatus;

        protected void OnExcuted(ExcutedTask Task, ExcutedResult result)
        {
            if (Excuted != null)
            {
                Excuted(this, new ExcutedEventArgs(Task, result, this._nextStatus));
            }
        }

        public string Name
        {
            get { return _name; }
        }

        public NameValueCollection ExtendableConfig
        {
            get{ return this._extendableConfig; }
            set { this._extendableConfig = value; }
        }

        public BizProcessBase NextBizProcess
        {
            get { return this._nextBizProcess; }
            set { this._nextBizProcess = value; }
        }

        public string NextStatus
        {
            get { return this._nextStatus.ToString(); }
            set { this._nextStatus =Int32.Parse(value); }
        }

        public BizProcessBase(string Name)
        {
            this._name = Name;
            this._extendableConfig = new NameValueCollection();
        }

        public void StartWorkThread()
        {
            _worker = new Thread(() => Work());
            _worker.Start();
        }

        public void StopWorkThread()
        {
           this.Enqueue(null);
        }
        
        //Can be Produced
        public void Enqueue(ExcutedTask task)
        {
            lock (_locker)
            {
                _tasks.Enqueue(task);
            }
            _wh.Set();
        }
      
        private void Work()
        {
            while (true)
            {
                ExcutedTask task = null;
                lock (_locker)
                {
                    if (this._tasks.Count > 0)
                    {
                        task = this._tasks.Dequeue();
                        if (task == null)
                        {
                            return;
                        }
                    }
                }
                if (task != null)
                {
                    Excute(task);
                    //Auto Triger Next Process
                    if (this._nextBizProcess != null)
                    {
                        this._nextBizProcess.Enqueue(task);
                    }
                }
                else
                    _wh.WaitOne();
            }
        }
        public abstract void Excute(ExcutedTask task);
        public abstract BizProcessBase Copy();
    }

    public enum ExcutedResult
    {
        Failure = 0,
        Successful = 1
    }
   
    public class ExcutedEventArgs : EventArgs
    {
        private ExcutedTask task;
        private ExcutedResult _result;
        private int _nextStatus;

        public ExcutedEventArgs(ExcutedTask Task, ExcutedResult result, int nextStatus)
        {
            this.task = Task;
            this._result = result;
            this._nextStatus = nextStatus;
        }

        public ExcutedTask Task
        {
            get { return this.task; }
        }

        public ExcutedResult Result
        {
            get { return this._result; }
        }

        public int NextStatus
        {
            get { return this._nextStatus; }
        }

    }
}
